﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Diagnostics;
using System.Threading;
using Quark.Framework;
using Quark.Framework.Collections.Concurrent;
using Quark.Framework.Logging;
using Quark.Profiler.Framework;

namespace Quark.Profiler.Server
{
    /// <summary>
    /// 测试服务端的缺省实现
    /// </summary>
    public abstract class GenericQuarkProfilerServer : IQuarkProfilerServer
    {
        #region Constants

        protected const string QUARK_PROFILER_USER_DIRECTORY = "Quark.Profiler";
        protected const string QUARK_PROFILER_USER_PROJECTS_DIRECTORY = "Projects";
        protected const string QUARK_PROFILER_PROJECT_EXT = ".profiler";
        protected const string NORMAL_LOGGER = "NormalLogger";
        protected const string ERROR_LOGGER = "ErrorLogger";
        protected const string PROF_LOGGER = "ProfilingLogger";

        #endregion

        #region Project Runtime State

        public enum ProfilingTestProjectState : int
        {
            NotStart,
            Running,
            Stopped,
            Finished
        }

        #endregion

        #region ProfilingContext

        public class ProfilingContext : IProfilingContext
        {
            #region Members

            protected GenericQuarkProfilerServer _server;
            protected ProfilingTestProject _project;

            #endregion

            #region Constructors

            public ProfilingContext(GenericQuarkProfilerServer server, ProfilingTestProject project)
            {
                this._server = server;
                this._project = project;
            }

            #endregion

            #region IProfilingContext 成员

            public IProfilingVisualizer GetProfilingVisualizer(ProfilingTestCase testCase)
            {
                return this._server.CreateProfilingVisualizer(testCase);
            }

            public IProfilingVisualizer GetProfilingVisualizer(IProfilingActivity activity)
            {
                return this._server.CreateProfilingVisualizer(activity);
            }

            public void LogInfo(object sender, string message)
            {
                ILog logger = this._server.GetNormalLogger();
                if (sender != null)
                {
                    if (sender is ProfilingTestProject) logger.Info(
                         string.Format(ResProfilerServer.TestProjectLogMessage, ((ProfilingTestProject)sender).Title, message));
                    else if (sender is ProfilingTestCase) logger.Info(
                         string.Format(ResProfilerServer.TestCaseLogMessage, ((ProfilingTestCase)sender).Title, message));
                    else logger.Info(message);
                }
                else logger.Info(message);
            }

            public void LogProfilingInfo(object sender, string message)
            {
                ILog logger = this._server.GetNormalLogger();
                if (sender != null)
                {
                    if (sender is ProfilingTestProject) logger.Info(
                         string.Format(ResProfilerServer.TestProjectProfilingLogMessage, ((ProfilingTestProject)sender).Title, message));
                    else if (sender is ProfilingTestCase) logger.Info(
                         string.Format(ResProfilerServer.TestCaseProfilingLogMessage, ((ProfilingTestCase)sender).Title, message));
                    else logger.Info(string.Format(ResProfilerServer.ProfilingLogMessage, message));
                }
                else logger.Info(string.Format(ResProfilerServer.ProfilingLogMessage, message));
            }

            public void LogError(object sender, string message)
            {
                ILog logger = this._server.GetErrorLogger();
                if (sender != null)
                {
                    if (sender is ProfilingTestProject) logger.Error(
                         string.Format(ResProfilerServer.TestProjectLogMessage, ((ProfilingTestProject)sender).Title, message));
                    else if (sender is ProfilingTestCase) logger.Error(
                         string.Format(ResProfilerServer.TestCaseLogMessage, ((ProfilingTestCase)sender).Title, message));
                    else logger.Error(message);
                }
                else logger.Error(message);
            }

            public void LogException(object sender, string message, Exception exception)
            {
                ILog logger = this._server.GetErrorLogger();
                if (sender != null)
                {
                    if (sender is ProfilingTestProject) logger.Error(
                         string.Format(ResProfilerServer.TestProjectLogMessage, ((ProfilingTestProject)sender).Title, message), exception);
                    else if (sender is ProfilingTestCase) logger.Error(
                         string.Format(ResProfilerServer.TestCaseLogMessage, ((ProfilingTestCase)sender).Title, message), exception);
                    else logger.Error(message, exception);
                }
                else logger.Error(message, exception);
            }

            #endregion
        }

        #endregion

        #region Members

        protected IQuarkProfilerServerConsole _console;
        protected ConcurrentDictionary<string, ProfilingTestProject> _projects;
        protected ConcurrentDictionary<ProfilingTestProject, ProfilingTestProjectState> _states;
        protected ILog _normalLogger;
        protected ILog _errorLogger;
        protected ILog _profilingLogger;

        #endregion

        #region Constructors

        public GenericQuarkProfilerServer()
        {
        }

        #endregion

        #region Paths

        protected virtual string ProfilerUserDirectory
        {
            get
            {
                string path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
                    + @"\" + QUARK_PROFILER_USER_DIRECTORY;

                if (!Directory.Exists(path))
                {
                    try { Directory.CreateDirectory(path); }
                    catch { }
                }

                return path;
            }
        }

        /// <summary>
        /// 获取配置文件所在目录
        /// </summary>
        protected virtual string ProfilerProjectsDirectory
        {
            get
            {
                string path = this.ProfilerUserDirectory + @"\" + QUARK_PROFILER_USER_PROJECTS_DIRECTORY;

                if (!Directory.Exists(path))
                {
                    try { Directory.CreateDirectory(path); }
                    catch { }
                }

                return path;
            }
        }

        #endregion

        #region Configuration Management

        protected void LoadConfiguration()
        {
        }

        #endregion

        #region Projects Management

        protected void ClearProjects()
        {
            this._projects.Clear();
            this._states.Clear();
        }

        protected void LoadProjects()
        {
            string[] files = Directory.GetFiles(this.ProfilerProjectsDirectory, "*" + QUARK_PROFILER_PROJECT_EXT);
            StringBuilder sbEx = new StringBuilder();

            foreach (string file in files)
            {
                try
                {
                    ProfilingTestProject project = ProfilingTestProject.LoadProject(file);
                    this._projects[project.Id] = project;
                    this._states[project] = ProfilingTestProjectState.NotStart;
                }
                catch (Exception ex)
                {
                    sbEx.AppendLine(string.Format(ResProfilerServer.LoadProfilingTestProjectEx, Path.GetFileName(file), ex.Message));
                }
            }

            if (sbEx.Length > 0)
            {
                throw new LoadProfilerTestProjectException(sbEx.ToString());
            }
        }

        #endregion

        #region UI

        protected abstract IProfilingVisualizer CreateProfilingVisualizer(ProfilingTestCase testCase);
        protected abstract IProfilingVisualizer CreateProfilingVisualizer(IProfilingActivity testActivity);

        #endregion

        #region Logging

        protected void InitializeLoggers()
        {
            this._normalLogger = LogManager.GetLogger(NORMAL_LOGGER);
            this._errorLogger = LogManager.GetLogger(ERROR_LOGGER);
            this._profilingLogger = LogManager.GetLogger(PROF_LOGGER);
        }

        protected ILog GetNormalLogger()
        {
            return this._normalLogger;
        }

        protected ILog GetErrorLogger()
        {
            return this._errorLogger;
        }

        protected ILog GetProfilingLogger()
        {
            return this._profilingLogger;
        }

        #endregion

        #region IQuarkProfilerServer 成员

        public IQuarkProfilerServerConsole Console
        {
            get { return this._console; }
        }

        public void InitializeProfilerServer(IQuarkProfilerServerConsole console)
        {
            if (console == null) throw new ArgumentNullException("console");

            this._console = console;
            this._projects = new ConcurrentDictionary<string, ProfilingTestProject>();
            this._states = new ConcurrentDictionary<ProfilingTestProject, ProfilingTestProjectState>();

            this.LoadConfiguration();
            this.LoadProjects();
            this.InitializeLoggers();
        }

        public void StartProfilerServer()
        {
        }

        public void StopProfilerServer()
        {
        }

        public ProfilingTestProject GetProfilingTestProject(string projectId)
        {
            ProfilingTestProject project = null;
            this._projects.TryGetValue(projectId, out project);

            return project;
        }

        public ProfilingTestProject[] GetAllProfilingTestProjects()
        {
            return this._projects.Values.ToArray();
        }

        public ProfilingTestProject[] GetAllStartedProfilingTestProjects()
        {
            var runningProject = from kv in this._states
                                 where kv.Value == ProfilingTestProjectState.Running
                                 select kv.Key;
            return runningProject.ToArray();
        }

        public IProfilingContext GetProfilingContext(ProfilingTestProject project)
        {
            return new ProfilingContext(this, project);
        }

        #endregion
    }
}
